import ast

from .ply.lex import Lexer
from .ply.yacc import yacc, LRParser

__all__ = ['get_parser']

def get_parser(lexer: Lexer, tokens: list[str]) -> LRParser:
    def p_module(p):
        'module : body'
        p[0] = ast.Module(
            body=p[1],
            type_ignores=[]
        )

    def p_cons(p):
        '''
        cons : pattern
        | NAME 为 pattern
        | cons 和 NAME 为 pattern
        | pattern 和 cons
        '''
        match p[1:]:
            case str() as name, '为', pattern:
                p[0] = {'kwd_attrs': [name], 'kwd_patterns': [pattern], 'patterns': []}
            case cons, '和', str() as name, '为', pattern:
                cons['kwd_attrs'].append(name)
                cons['kwd_patterns'].append(pattern)
                p[0] = cons
            case pattern, '和', cons:
                cons['patterns'].append(pattern)
                p[0] = cons
            case pattern:
                p[0] = {'kwd_attrs': [], 'kwd_patterns': [], 'patterns': [pattern]}

    def p_pattern_class(p):
        '''
        pattern : 类型为 expr
        | 以 cons 构造 expr
        '''
        match p[1:]:
            case '类型为', cls:
                p[0] = ast.MatchClass(
                    cls=cls,
                    patterns=[],
                    kwd_attrs=[],
                    kwd_patterns=[]
                )
            case '以', cons, '构造', cls:
                p[0] = ast.MatchClass(
                    cls=cls,
                    **cons
                )

    def p_mappingitem(p):
        '''
        mappingitem : const 对应 pattern
        | 剩下 NAME
        | mappingitem 和 const 对应 pattern
        | mappingitem 和 剩下 NAME
        '''
        match p[1:]:
            case ast.MatchMapping() as mapping, '和', key, '对应', pattern:
                mapping.keys.append(key)
                mapping.patterns.append(pattern)
                p[0] = mapping
            case ast.MatchMapping() as mapping, '和', '剩下', str() as name:
                mapping.rest = name
                p[0] = mapping
            case key, '对应', pattern:
                p[0] = ast.MatchMapping(
                    keys=[key],
                    patterns=[pattern],
                    rest=None
                )
            case '剩下', str() as name:
                p[0] = ast.MatchMapping(
                    keys=[],
                    patterns=[],
                    rest=name
                )

    def p_pattern_mapping(p):
        'pattern : 有 mappingitem 的映射'
        p[0] = p[2]

    def p_pattern_singleton(p):
        'pattern : reservedconst'
        p[0] = ast.MatchSingleton(
            value=p[1]
        )

    def p_pattern_value(p):
        'pattern : const'
        p[0] = ast.MatchValue(
            value=p[1]
        )

    def p_pattern(p):
        '''
        pattern : 有 patternseq 的序列
        | patternor
        '''
        match p[1:]:
            case '有', patternseq, '的序列':
                p[0] = patternseq
            case [patternor]:
                p[0] = patternor

    def p_pattern_sequence(p):
        '''
        patternseq : patternseq 和 pattern
        | pattern
        '''
        match p[1:]:
            case ast.MatchSequence() as patternseq, '和', pattern:
                patternseq.patterns.append(pattern)
                p[0] = patternseq
            case [pattern]:
                p[0] = ast.MatchSequence(
                    patterns=[pattern]
                )

    def p_pattern_star(p):
        'pattern : 变长 NAME'
        p[0] = ast.MatchStar(
            name=p[2]
        )

    def p_pattern_or(p):
        '''
        patternor : pattern 或 pattern
        | patternor 或 pattern
        '''
        match p[1:]:
            case ast.MatchOr() as patternor, '或', pattern:
                patternor.patterns.append(pattern)
                p[0] = patternor
            case left, '或', right:
                p[0] = ast.MatchOr(
                    patterns=[left, right]
                )

    def p_pattern_as(p):
        '''
        pattern : pattern 为 NAME
        | NAME
        | 弃元
        '''
        match p[1:]:
            case ['弃元']:
                p[0] = ast.MatchAs(
                    pattern=None,
                    name=None
                )
            case [str() as name]:
                p[0] = ast.MatchAs(
                    pattern=None,
                    name=name
                )
            case pattern, '为', str() as name:
                p[0] = ast.MatchAs(
                    pattern=pattern,
                    name=name
                )

    def p_case(p):
        '''
        case : 符合 pattern 且 expr 时 body
        | 符合 pattern 时 body
        '''
        match p[2:]:
            case pattern, '且', guard, '时', body:
                p[0] = ast.match_case(
                    pattern=pattern,
                    guard=guard,
                    body=body
                )
            case pattern, '时', body:
                p[0] = ast.match_case(
                    pattern=pattern,
                    guard=None,
                    body=body
                )

    def p_stmt_match(p):
        'stmt : match'
        p[0] = stmtify(p[1])

    def p_match(p):
        '''
        match : 匹配 expr case
        | match case
        '''
        match p[1:]:
            case '匹配', subject, ast.match_case() as case:
                p[0] = ast.Match(
                    subject=subject,
                    cases=[case]
                )
            case ast.Match() as match, ast.match_case() as case:
                match.cases.append(case)
                p[0] = match

    def p_await(p):
        'expr : 等待 expr'
        p[0] = ast.Await(
            value=p[2]
        )

    def p_del(p):
        'stmt : 删除 left'
        p[0] = stmtify(ast.Delete(
            targets=[p[2]]
        ))

    def p_class(p):
        '''
        classdef : 定义类 NAME body
        | 定义类 NAME 派生自 args body
        '''
        cls = ast.ClassDef(
            name=p[2],
            body=p[len(p) - 1],
            decorator_list=[]
        )
        match p[3:]:
            case '派生自', dict() as args, _:
                cls.bases = args['args']
                cls.keywords = args['keywords']
            case _:
                cls.bases = []
                cls.keywords = []
        p[0] = cls

    def p_stmt_with(p):
        'stmt : with'
        p[0] = stmtify(p[1])

    def p_async_with(p):
        'with : 异步 with'
        p[0] = ast.AsyncWith(**vars(p[2]))

    def p_with(p):
        'with : withhead body'
        p[1].body = p[2]
        p[0] = p[1]

    def p_withhead(p):
        '''
        withhead : 持有 withitem
        | withhead 和 withitem
        '''
        match p[1:]:
            case '持有', ast.withitem() as item:
                p[0] = ast.With(
                    items=[item]
                )
            case ast.With() as stmt, '和', ast.withitem() as item:
                stmt.items.append(item)
                p[0] = stmt

    def p_withitem(p):
        '''
        withitem : expr
        | expr 为 augleft
        '''
        p[0] = ast.withitem(
            context_expr=p[1],
            optional_vars=None if len(p) == 2 else p[3]
        )

    def p_alias(p):
        '''
        alias : expr
        | expr 为 NAME
        '''
        p[0] = (p[1], None if len(p) == 2 else p[3])

    def p_handler(p):
        '''
        handler : 捕获异常 alias body
        | 如果有异常 body
        '''
        match p[1:]:
            case '捕获异常', tuple() as alias, body:
                p[0] = ast.ExceptHandler(
                    type=alias[0],
                    name=alias[1],
                    body=body
                )
            case '如果有异常', body:
                p[0] = ast.ExceptHandler(
                    type=None,
                    name=None,
                    body=body
                )

    def p_tryhead(p):
        '''
        tryhead : 尝试 body
        | tryhead handler
        '''
        if p[1] == '尝试':
            p[0] = ast.Try(
                body=p[2],
                handlers=[],
                orelse=[],
                finalbody=[]
            )
        else:
            p[1].handlers.append(p[2])
            p[0] = p[1]

    def p_try(p):
        '''
        stmt : tryhead
        | tryhead 然后 body
        | tryhead 总之 body
        | tryhead 然后 body 总之 body
        '''
        match p[1:]:
            case head, '然后', orelse:
                head.orelse = orelse
            case head, '总之', finalbody:
                head.finalbody = finalbody
            case head, '然后', orelse, '总之', finalbody:
                head.orelse = orelse
                head.finalbody = finalbody
        p[0] = stmtify(p[1])

    def p_throw(p):
        '''
        stmt : 抛出 expr
        | 从 expr 抛出 expr
        '''
        p[0] = stmtify(ast.Raise(
            exc=p[2] if len(p) == 3 else p[4],
            cause=None if len(p) == 3 else p[2]
        ))

    def p_assert(p):
        '''
        stmt : 断言 expr
        | 断言 expr 如果失败 expr
        '''
        p[0] = stmtify(ast.Assert(
            test=p[2],
            msg=None if len(p) == 3 else p[4]
        ))

    def p_importalias(p):
        '''
        importalias : NAME 为 NAME
        | NAME
        | importalias 和 NAME 为 NAME
        | importalias 和 NAME
        '''
        namealias(p)

    def p_stmt_import(p):
        '''
        stmt : import 
        | fromimport
        '''
        p[0] = stmtify(p[1])

    def p_fromimport(p):
        '''
        fromimport : 从 importname 导入 importalias
        | 从 前 INT 级 导入 importalias
        | 从 前 INT 级的 importname 导入 importalias
        | 从 importname 导入所有
        | 从 前 INT 级 导入所有
        | 从 前 INT 级的 importname 导入所有
        '''
        length = len(p)
        if p[length - 1] == '导入所有':
            p[0] = ast.ImportFrom(
                names=[ast.alias(
                    name='*',
                    asname=None
                )]
            )
            length += 1
        else:
            p[0] = ast.ImportFrom(
                names=p[length - 1]
            )
        match p[2:]:
            case '前', int() as level, '级的', str() as module, *_:
                p[0].level = level
                p[0].module = module
            case '前', int() as level, '级', *_:
                p[0].level = level
                p[0].module = None
            case str() as module, *_:
                p[0].level = 0
                p[0].module = module

    def p_importname(p):
        '''
        importname : NAME
        | importname 的 NAME
        '''
        match p[1:]:
            case [str() as name]:
                p[0] = name
            case str() as name, '的', str() as ext:
                p[0] = name + '.' + ext

    def namealias(p):
        match p[1:]:
            case [str() as name]:
                p[0] = [ast.alias(
                    name=name,
                    asname=None
                )]
            case str() as name, '为', str() as asname:
                p[0] = [ast.alias(
                    name=name,
                    asname=asname
                )]
            case list() as names, '和', str() as ext:
                names.append(ast.alias(
                    name=ext,
                    asname=None
                ))
                p[0] = names
            case list() as names, '和', str() as ext, '为', str() as asname:
                names.append(ast.alias(
                    name=ext,
                    asname=asname
                ))
                p[0] = names

    def p_importnamealias(p):
        '''
        importnamealias : importname
        | importname 为 NAME
        | importnamealias 和 importname
        | importnamealias 和 importname 为 NAME
        '''
        namealias(p)

    def p_import(p):
        '''
        import : 导入 importnamealias
        '''
        p[0] = ast.Import(
            names=p[2]
        )

    def p_names(p):
        '''
        names : NAME
        | names 和 NAME
        '''
        match p[1:]:
            case [str() as name]:
                p[0] = [name]
            case list() as names, '和', str() as name:
                names.append(name)
                p[0] = names

    def p_extern(p):
        '''
        stmt : 声明 names 为全局
        | 声明 names 为非局部
        '''
        p[0] = stmtify((ast.Global if p[3] == '为全局' else ast.Nonlocal)(
            names=p[2]
        ))

    def p_yield_from(p):
        'expr : 从 expr 产出'
        p[0] = ast.YieldFrom(
            value=p[2]
        )

    def p_yield(p):
        '''
        expr : 产出
        | 产出 expr
        '''
        p[0] = ast.Yield(
            value=None if len(p) == 2 else p[2]
        )

    def p_return(p):
        '''
        stmt : 返回
        | 返回 expr
        '''
        p[0] = stmtify(ast.Return(
            value=None if len(p) == 2 else p[2]
        ))

    def p_elems(p):
        '''
        elems : expr
        | unpack
        | elems 和 expr
        | elems 和 unpack
        '''
        match p[1:]:
            case list() as elems, '和', elem:
                elems.append(elem)
                p[0] = elems
            case [elem]:
                p[0] = [elem]

    def p_stmt_deco(p):
        'stmt : deco'
        p[0] = stmtify(p[1])

    def p_deco(p):
        '''
        deco : 以 expr 修饰 deco
        | funcdef
        | classdef
        '''
        match p[1:]:
            case '以', decorator, '修饰', stmt:
                stmt.decorator_list.append(decorator)
                p[0] = stmt
            case [stmt]:
                p[0] = stmt

    def p_param(p):
        '''
        param : NAME
        | 变长 NAME
        | expr 类型的 param
        '''
        match p[1:]:
            case [str() as name]:
                p[0] = ast.arg(
                    arg=name,
                    annotation=None,
                    vararg=False
                )
            case '变长', str() as name:
                p[0] = ast.arg(
                    arg=name,
                    annotation=None,
                    vararg=True
                )
            case type, '类型的', ast.arg() as arg:
                arg.annotation = type
                p[0] = arg

    def p_kwparam(p):
        '''
        kwparam : NAME 为 expr
        | 变长映射 NAME
        | expr 类型的 kwparam
        '''
        match p[1:]:
            case str() as name, '为', default:
                p[0] = ast.arg(
                    arg=name,
                    annotation=None,
                    default=default
                )
            case '变长映射', str() as name:
                p[0] = ast.arg(
                    arg=name,
                    annotation=None,
                    default=None
                )
            case type, '类型的', ast.arg() as arg:
                arg.annotation = type
                p[0] = arg

    def empty_arguments():
        return ast.arguments(
                args=[],
                posonlyargs=[],
                kwonlyargs=[],
                varargs=[],
                kw_defaults=[],
                kwargs=[],
                defaults=[]
            )

    def p_params(p):
        '''
        params : param 和 params
        | params 之前为位置参数
        | 之后为关键字参数 params
        | params 和 kwparam
        | kwparam
        | param
        '''
        def addkwparam(params, kwparam):
            if kwparam.default is not None:
                params.args.append(kwparam)
                params.defaults.append(kwparam.default)
            else:
                params.kwarg = kwparam
        def addparam(params, param):
            if param.vararg:
                params.vararg = param
            else:
                params.args.append(param)
        match p[1:]:
            case [ast.arg() as param_or_kwparam]:
                p[0] = empty_arguments()
                if hasattr(param_or_kwparam, 'vararg'):
                    addparam(p[0], param_or_kwparam)
                else:
                    addkwparam(p[0], param_or_kwparam)
            case ast.arguments() as params, '和', ast.arg() as kwparam:
                addkwparam(params, kwparam)
                p[0] = params
            case '之后为关键字参数', ast.arguments() as params:
                params.kwonlyargs = params.args
                params.args = []
                params.kw_defaults = params.defaults
                params.defaults = []
                p[0] = params
            case ast.arguments() as params, '之前为位置参数':
                params.posonlyargs = params.args
                params.args = []
                p[0] = params
            case ast.arg() as param, '和', ast.arguments() as params:
                addparam(params, param)
                p[0] = params

    def p_expr_genexpr(p):
        'expr : genexpr'
        p[0] = p[1]

    def p_collection_comp(p):
        '''
        factor : genexpr 到列表
        | genexpr 到集合
        | comp 为 expr 对应 expr 到字典
        '''
        match p[1:]:
            case ast.GeneratorExp() as genexpr, '到列表' | '到集合' as type:
                p[0] = (ast.ListComp if type == '到列表' else ast.SetComp)(**vars(p[1]))
            case ast.comprehension() as comp, '为', key, '对应', value, '到字典':
                p[0] = ast.DictComp(
                    key=key,
                    value=value,
                    generators=[p[1]]
                )

    def p_genexpr(p):
        'genexpr : comp 为 expr'
        p[0] = ast.GeneratorExp(
            elt=p[3],
            generators=[p[1]]
        )

    def p_async_comp(p):
        'comp : 异步 comp'
        p[2].is_async = 1
        p[0] = p[2]

    def p_comp(p):
        '''
        comp : 选取 expr 中的成员 left
        | 选取 expr 中 expr 的成员 left
        '''
        p[0] = ast.comprehension(
            target=p[len(p) - 1],
            iter=p[2],
            ifs=[] if len(p) == 5 else [p[4]],
            is_async=0
        )

    def p_lambda(p):
        '''
        expr : 返回 expr 的匿名函数
        | 接受 params 返回 expr 的匿名函数
        '''
        p[0] = ast.Lambda(
            args=empty_arguments() if len(p) == 4 else p[2],
            body=p[len(p) - 2]
        )

    def p_async_def(p):
        'funcdef : 异步 funcdef'
        p[0] = ast.AsyncFunctionDef(**vars(p[2]))

    def p_def(p):
        '''
        funcdef : 定义函数 NAME body
        | 定义函数 NAME 以 params 为参数 body
        | 定义返回 expr 的函数 NAME body
        | 定义返回 expr 的函数 NAME 以 params 为参数 body
        '''
        func = ast.FunctionDef(
            body=p[len(p) - 1],
            decorator_list=[],
            args=empty_arguments(),
            returns=None
        )
        match p[1:]:
            case '定义函数', str() as name, _:
                func.name = name
            case '定义函数', str() as name, '以', ast.arguments() as params, '为参数', _:
                func.name = name
                func.args = params
            case '定义返回', returns, '的函数', str() as name, _:
                func.name = name
                func.returns = returns
            case '定义返回', returns, '的函数', str() as name, '以', ast.arguments() as params, '为参数', _:
                func.name = name
                func.returns = returns
                func.args = params
        p[0] = func

    def p_dictitem(p):
        '''
        dictitem : expr 对应 expr
        | dictitem 和 expr 对应 expr
        '''
        match p[1:]:
            case key, '对应', value:
                p[0] = ast.Dict(
                    keys=[p[1]],
                    values=[p[3]]
                )
            case ast.Dict() as dict, '和', key, '对应', value:
                dict.keys.append(key)
                dict.values.append(value)
                p[0] = dict

    def p_dict(p):
        'factor : 有 dictitem 的字典'
        p[0] = p[2]

    def p_collection(p):
        '''
        factor : 有 elems 的列表
        | 有 elems 的集合
        | 有 elems 的元组
        '''
        p[0] = {
            '的列表': ast.List,
            '的集合': ast.Set,
            '的元组': ast.Tuple
        }[p[3]](
            elts=p[2],
            ctx=None
        )

    def p_empty_collection(p):
        '''
        factor : 空列表
        | 空元组
        | 空集合
        | 空字典
        '''
        if p[1] == '空字典':
            p[0] = ast.Dict(
                keys=[],
                values=[]
            )
        else:
            p[0] = {
                '空列表': ast.List,
                '空元组': ast.Tuple,
                '空集合': ast.Set
            }[p[1]](
                elts=[],
                ctx=None
            )

    def p_pass(p):
        'stmt : 跳过'
        p[0] = stmtify(ast.Pass())

    def p_annotation(p):
        'stmt : augleft 类型为 expr'
        p[0] = stmtify(ast.AnnAssign(
            target=p[1],
            annotation=p[3],
            value=None,
            simple=0
        ))

    def p_annassign(p):
        'stmt : 赋值 expr 类型的 augleft 为 expr'
        p[0] = stmtify(ast.AnnAssign(
            target=p[4],
            annotation=p[2],
            value=p[6],
            simple=0
        ))

    def p_body(p):
        '''
        body : stmts 以上
        | stmt
        | stmt 以上
        '''
        p[0] = p[1]

    def p_stmts(p):
        '''
        stmts : stmt
        | stmt 接着 stmts
        '''
        match p[1:]:
            case list() as stmt, '接着', list() as stmts:
                p[0] = stmt + stmts
            case list() as stmt:
                p[0] = stmt[0]

    def p_stmt_expr(p):
        'stmt : expr'
        p[0] = stmtify(ast.Expr(
            value=p[1]
        ))
        
    def p_args(p):
        '''
        args : arg 和 args
        | args 和 kwarg
        | arg
        | kwarg
        '''
        match p[1:]:
            case arg, '和', dict() as args:
                args['args'].insert(0, arg)
                p[0] = args
            case dict() as args, '和', ast.keyword() as kwarg:
                args['keywords'].append(kwarg)
                p[0] = args
            case [ast.keyword() as kwarg]:
                p[0] = {'args': [], 'keywords': [kwarg]}
            case [arg]:
                p[0] = {'args': [arg], 'keywords': []}

    def p_kwarg(p):
        '''
        kwarg : NAME 为 expr
        | unpackmapping
        '''
        match p[1:]:
            case str() as key, '为', value:
                p[0] = ast.keyword(
                    arg=key,
                    value=value
                )
            case ast.keyword() as unpack_mapping:
                p[0] = unpack_mapping

    def p_arg(p):
        '''
        arg : expr
        | unpack
        '''
        p[0] = p[1]

    def p_call(p):
        '''
        factor : 直接调用 factor
        | 以 args 调用 factor
        '''
        p[0] = ast.Call(
            func=p[2] if len(p) == 3 else p[4],
            **({'args': [], 'keywords': []} if len(p) == 3 else p[2])
        )

    def p_loop_control(p):
        '''
        stmt : 跳出
        | 重新
        '''
        p[0] = stmtify(ast.Break() if p[1] == '跳出' else ast.Continue())

    def p_stmt_for(p):
        'stmt : for'
        p[0] = stmtify(p[1])

    def p_for(p):
        '''
        for : 对于 expr 中的每一个 left body
        | 对于 expr 中的每一个 left body 然后 body
        '''
        p[0] = ast.For(
            target=p[4],
            iter=p[2],
            body=p[5],
            orelse=[] if len(p) == 6 else p[7]
        )

    def p_async_for(p):
        'for : 异步 for'
        p[0] = ast.AsyncFor(**vars(p[2]))

    def p_ifexpr(p):
        'expr : expr 如果 expr 否则 expr'
        p[0] = ast.IfExp(
            test=p[3],
            body=p[1],
            orelse=p[5]
        )

    def p_while(p):
        '''
        stmt : 当 expr 时 body
        | 当 expr 时 body 然后 body
        '''
        p[0] = stmtify(ast.While(
            test=p[2],
            body=p[4],
            orelse=[] if len(p) == 5 else p[6]
        ))

    def p_if(p):
        '''
        stmt : 如果 expr body
        | 如果 expr body 否则 body
        '''
        p[0] = stmtify(ast.If(
            test=p[2],
            body=p[3],
            orelse=[] if len(p) == 4 else p[5]
        ))

    def p_assign(p):
        'stmt : 赋值 left 为 expr'
        p[0] = stmtify(ast.Assign(
            targets=[p[2]],
            value=p[4]
        ))

    def p_update(p):
        'stmt : 更新 augleft bop expr'
        p[0] = stmtify(ast.AugAssign(
            target=p[2],
            op=p[3],
            value=p[4]
        ))

    def p_bop_op(p):
        '''bop : 加
        | 减
        | 乘
        | 除
        | 整除
        | 取模
        | 乘方
        | 矩阵乘法
        | 左移
        | 右移
        | 位或
        | 位和
        | 异或
        '''
        p[0] = {
            '加': ast.Add(),
            '减': ast.Sub(),
            '乘': ast.Mult(),
            '除': ast.Div(),
            '整除': ast.FloorDiv(),
            '取模': ast.Mod(),
            '乘方': ast.Pow(),
            '矩阵乘法': ast.MatMult(),
            '左移': ast.LShift(),
            '右移': ast.RShift(),
            '位或': ast.BitOr(),
            '位和': ast.BitAnd(),
            '异或': ast.BitXor()
        }[p[1]]

    def p_augleft(p):
        '''
        augleft : name
        | attr
        | subscript
        '''
        p[0] = p[1]

    def p_left(p):
        '''
        left : augleft
        | tuple
        '''
        p[0] = p[1]

    def p_tuple(p):
        '''
        tuple : elems
        '''
        p[0] = ast.Tuple(
            elts=p[1],
            ctx=None
        )

    def p_expr(p):
        '''
        expr : or
        | and
        | bexpr
        '''
        p[0] = p[1]

    def p_nameexpr(p):
        'expr : name 赋值为 expr'
        p[0] = ast.NamedExpr(
            target=p[1],
            value=p[3]
        )

    def p_or(p):
        '''
        or : and
        | bexpr
        | or 或 and
        | or 或 bexpr
        '''
        gen_boolop(p, ast.Or())

    def p_and(p):
        '''
        and : bexpr
        | and 且 bexpr
        '''
        gen_boolop(p, ast.And())

    def p_bop(p):
        '''
        bexpr : bitexpr
        | cmp'''
        p[0] = p[1]

    def p_cmp(p):
        '''
        cmp : bitexpr
        | cmp 是 cmp
        | cmp 不是 cmp
        | cmp 在 cmp
        | cmp 不在 cmp
        | cmp 等于 cmp
        | cmp 不等于 cmp
        | cmp 大于 cmp
        | cmp 小于等于 cmp
        | cmp 小于 cmp
        | cmp 大于等于 cmp
        '''
        match p[1:]:
            case left, str() as op, right:
                left.comparators.append(right)
                left.ops.append({
                    '是': ast.Is(),
                    '不是': ast.IsNot(),
                    '在': ast.In(),
                    '不在': ast.NotIn(),
                    '等于': ast.Eq(),
                    '不等于': ast.NotEq(),
                    '大于': ast.Gt(),
                    '小于等于': ast.LtE(),
                    '小于': ast.Lt(),
                    '大于等于': ast.GtE(),
                }[op])
                p[0] = p[1]
            case [bitexpr]:
                p[0] = ast.Compare(
                    left=bitexpr,
                    ops=[],
                    comparators=[]
                )

    def p_bitop(p):
        '''
        bitexpr : andexpr
        | bitexpr 位或 bitexpr
        | bitexpr 异或 bitexpr
        '''
        gen_binop(p, {
            '位和': ast.BitOr(),
            '异或': ast.BitXor()
        })

    def p_andop(p):
        '''
        andexpr : shexpr
        | andexpr 位和 andexpr
        '''
        gen_binop(p, {'位和': ast.BitAnd()})

    def p_shop(p):
        '''
        shexpr : aexpr
        | shexpr 左移 shexpr
        | shexpr 右移
        '''
        gen_binop(p, {
            '左移': ast.LShift(),
            '右移': ast.RShift()
        })

    def p_aexpr(p):
        '''
        aexpr : term
        | aexpr 加 aexpr
        | aexpr 减 aexpr
        '''
        gen_binop(p, {
            '加': ast.Add(),
            '减': ast.Sub()
        })

    def p_term(p):
        '''
        term : power
        | term 乘 term
        | term 除 term
        | term 整除 term
        | term 取模 term
        '''
        gen_binop(p, {
            '乘': ast.Mult(),
            '除': ast.Div(),
            '整除': ast.FloorDiv(),
            '取模': ast.Mod()
        })

    def p_power(p):
        '''
        power : factor
        | power 乘方 power
        | power 矩阵乘法 power
        '''
        gen_binop(p, {
            '乘方': ast.Pow(),
            '矩阵乘法': ast.MatMult()
        })

    def p_uop(p):
        '''factor : 取反 factor
        | 正 factor
        | 负 factor
        | 不 factor
        '''
        p[0] = ast.UnaryOp(
            op={
                '取反': ast.Invert(),
                '正': ast.UAdd(),
                '负': ast.USub(),
                '不': ast.Not()
            }[p[1]],
            operand=p[2]
        )

    def p_factor_expr(p):
        'factor : 计算 expr 的值'
        p[0] = p[2]

    def p_factor(p):
        '''
        factor : const
        | attr
        | subscript
        | name
        '''
        p[0] = p[1]

    def p_attr(p):
        'attr : factor 的 NAME'
        p[0] = ast.Attribute(
            value=p[1],
            attr=p[3],
            ctx=None
        )

    def p_subscript(p):
        'subscript : factor 的第 expr 个'
        p[0] = ast.Subscript(
            value=p[1],
            slice=p[3],
            ctx=None
        )

    def p_slice_upper(p):
        '''
        sliceupper : expr
        | 最后
        '''
        if isinstance(p[1], str):
            p[0] = {}
        else:
            p[0] = {'upper': p[1]}

    def p_slice_lower(p):
        '''
        slicelower : expr
        | 开始
        '''
        if isinstance(p[1], str):
            p[0] = {}
        else:
            p[0] = {'lower': p[1]}

    def p_slice(p):
        '''
        subscript : factor 从 slicelower 到 sliceupper 的成员
        | factor 从 slicelower 到 sliceupper 每隔 expr 的成员
        '''
        p[0] = ast.Subscript(
            value=p[1],
            slice=ast.Slice(
                **p[3],
                **p[5],
                **({} if len(p) == 7 else {'step': p[7]})
            ),
            ctx=None
        )

    def p_str(p):
        '''
        str : STR
        | BSTR
        | RSTR
        | RBSTR
        | ESTR
        '''
        p[0] = p[1]

    def p_const(p):
        '''
        const : INT
        | FLOAT
        | str
        | reservedconst'''
        p[0] = ast.Constant(
            value=p[1]
        )

    def p_reserved_const(p):
        '''
        reservedconst : 真
        | 假
        | 无
        | 没什么
        '''
        p[0] = {
            '真': True,
            '假': False,
            '无': None,
            '没什么': ...
        }[p[1]]

    def p_name(p):
        'name : NAME'
        p[0] = ast.Name(
            id=p[1],
            ctx=None
        )

    def p_unpack_mapping(p):
        'unpackmapping : 解包映射 expr'
        p[0] = ast.keyword(
            arg=p[2],
            value=None
        )

    def p_unpack(p):
        'unpack : 解包 expr'
        p[0] = ast.Starred(p[2])

    def p_error(p):
        raise SyntaxError(f'在 {p} 的非法语法')

    def gen_binop(p, dict):
        match p[1:]:
            case left, str() as op, right:
                p[0] = ast.BinOp(
                    left=left,
                    op=dict[op],
                    right=right
                )
            case [lower]:
                p[0] = lower

    def gen_boolop(p, op):
        match p[1:]:
            case left, _, right:
                left.values.append(right)
            case [lower]:
                p[0] = ast.BoolOp(
                    op=op,
                    values=[lower]
                )

    def stmtify(stmt):
        stmt.lineno = 1
        return [stmt]

    return yacc()